﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace DrWileyO_REDACTED_Adventure
{
    class MainCharacter
    {
        //public Texture2D sprite;
        public AnimatedSprite sprite;
        public Texture2D debug;
        public Vector2 pos;
        public Rectangle hitBox;
        public SpriteFont sFont;

        public float gravity = .5f;

        public float speed = 2f;

        public bool isDead = false;
        public int deathCount = 0;

        public bool movingRight = true;

        public bool jumping = false;
        public bool apex = false;
        public bool walking = false;
        public float curVertiSpeed = 0f;
        public float lastStartHeight = 0f;
        public float lastButtonTime = -10.0f;
        public float lastTime = -1.0f;
        public float hangtime = 0.0f;
        public float jumpHeight;
        public float extraHeight;
        public float repeatTime = .05f;
        public float timeout = .15f;
        public float maxFallSpeed = 20f;
        public float curHeight = 0f;
        public double jumpTimer = 0.0;
        public const float standardJumpSpeed = 5f;
        public float initJumpSpeed = 5f;
        public float vertSpeed = 0;

        public bool starting = true;

        public float energy = 1f;
        public const float SHRINK_ENERGY = -0.005f;
        public const float STOP_ENERGY = -0.0005f;
        public const float NORMAL_ENERGY = -0.00025f;

        public float minScale = 0.25f;
        public float maxScale = 100.0f;
        public float range;

        public bool grounded = false;
        public bool hitCeiling = false;

        public bool shrinking = false;
        public bool toggleGrowOff = false;

        public const float SHRINK_SPEED = -0.05f;
        public const float GROW_SPEED = 0.005f;

        //sound timers
        double SHRINK_DELAY = 1000;
        double TAUNT_DELAY = 10000;
        
        double sShrinkTimer;
        double sTauntTimer;
        //end sound stuff

        //animation stuff
        double WALK_DELAY = 100;

        double aWalkTimer = 0;

        const int WALK1 = 0;
        const int WALK2 = 1;
        const int WALK3 = 2;
        const int JUMP1 = 3;
        const int JUMP2 = 4;

        int aWalkAniDir = 1;
        //end animation stuff

        float scaleDiff = 0;

        KeyboardState oldState;

        Random rand;

        public MainCharacter(Texture2D text, Vector2 position, Texture2D debug, SpriteFont font)
        {
            rand = new Random();

            oldState = new KeyboardState();

            range = maxScale - minScale;

            sShrinkTimer = SHRINK_DELAY;

            sprite = new AnimatedSprite(text, position, 1, 6);
            sprite.currentFrame = 2;
            pos = position;

            sFont = font;

            hitBox = sprite.destRect;
            jumpHeight = sprite.Height;
            extraHeight = 4 * jumpHeight;
            this.debug = debug;
        }

        public void Update(GameTime gameTime)
        {
            if (!isDead)
            {
                KeyboardState state = Keyboard.GetState();
                scaleDiff = 0;

                if (state.IsKeyDown(Keys.D) && !state.IsKeyDown(Keys.A))
                {
                    walking = true;
                    pos.X += speed;
                    movingRight = true;
                }
                else if (!state.IsKeyDown(Keys.D) && state.IsKeyDown(Keys.A))
                {
                    walking = true;
                    pos.X -= speed;
                    movingRight = false;
                }
                else
                {
                    walking = false;
                }

                float prevScale = sprite.Scale;

             /**   if (state.IsKeyDown(Keys.RightShift))
                {
                    ScaleSelf(0.05f, gameTime);
                } */
                if (state.IsKeyDown(Keys.Space))
                {
                    if (sprite.Scale > 0.3)
                    {
                        shrinking = true;
                        AlterEnergy(SHRINK_ENERGY);
                        ScaleSelf(SHRINK_SPEED, gameTime);
                    }
                    else
                    {
                        shrinking = false;
                        toggleGrowOff = true;
                    }
                    pos = new Vector2(pos.X - (sprite.Width * sprite.Scale - sprite.Width * prevScale), pos.Y - (sprite.Height * sprite.Scale - sprite.Height * prevScale));
                }
             /**   if (state.IsKeyDown(Keys.E) && oldState.IsKeyUp(Keys.E))
                {
                    toggleGrowOff = !toggleGrowOff;
                } */

                if (state.IsKeyUp(Keys.Space) && oldState.IsKeyDown(Keys.Space))
                {
                    shrinking = false;
                    toggleGrowOff = false;
                }
                if (state.IsKeyDown(Keys.W) && !jumping)
                {
                    SoundManager.Instance.playSound(SoundManager.Sound.jump);
                    jumping = true;
                    grounded = false;
                    jumpTimer = 0.0;
                }

                if (grounded)
                {
                    jumping = false;
                    apex = false;
                    curHeight = 0.0f;
                }

                if (jumping)
                    ApplyJumping(gameTime);

                if (!jumping || hitCeiling)
                {
                    pos.Y += 5;
                    hitCeiling = false;
                }

                hitBox = new Rectangle((int)pos.X, (int)pos.Y, (int)(sprite.Width * sprite.Scale), (int)(sprite.Height * sprite.Scale));


                if (!jumping)
                {
                    jumpHeight = sprite.Height * sprite.Scale;
                    extraHeight = 4 * jumpHeight;
                    initJumpSpeed = standardJumpSpeed * sprite.Scale;
                    if (initJumpSpeed >= standardJumpSpeed * 1.75f)
                    {
                        initJumpSpeed = standardJumpSpeed * 1.75f;
                    }
                    else if (initJumpSpeed <= standardJumpSpeed * .75f)
                    {
                        initJumpSpeed = standardJumpSpeed * .75f;
                    }
                }

                RandomTaunt(gameTime);
                UpdateSprite(gameTime);

                if (toggleGrowOff)
                    AlterEnergy(STOP_ENERGY);
                else if (!shrinking)
                    AlterEnergy(NORMAL_ENERGY);

                if (!toggleGrowOff)
                {
                    ScaleSelf(GROW_SPEED, gameTime);
                }

                pos.X -= scaleDiff * sprite.Width / 2;
                sprite.Update(gameTime, pos);

                oldState = state;
            }
            else
            {
                deathCount++;
            }
        }

        public void ApplyJumping(GameTime gameTime)
        {
            vertSpeed = initJumpSpeed + -9.8f * (float)jumpTimer / 1000;
            pos.Y -= vertSpeed;
            jumpTimer += gameTime.ElapsedGameTime.Milliseconds;
            curHeight += 8;
        }

        float CalculateJumpVerticalSpeed(float height)
        {
            return (float)Math.Sqrt(2 * height * gravity);
        }

        public void ScaleSelf(float scale, GameTime time)
        {
            if (sprite.Scale + scale < maxScale && sprite.Scale + scale > minScale)
            {
                if ((time.TotalGameTime.TotalMilliseconds - sShrinkTimer) >= SHRINK_DELAY && scale < 0)
                {
                    SoundManager.Instance.playSound(SoundManager.Sound.shrink);
                    sShrinkTimer = time.TotalGameTime.TotalMilliseconds;
                }

                scaleDiff += Math.Abs(scale);
                sprite.Scale += scale;
            }  
        }

        public void Draw(GameTime gameTime, SpriteBatch spriteBatch)
        {
            if (!isDead)
            {
                if (movingRight)
                {
                    if (shrinking)
                        sprite.Draw(spriteBatch, Color.LimeGreen);
                    else
                        sprite.Draw(spriteBatch);
                }
                else
                {
                    if (shrinking)
                        sprite.Draw(spriteBatch, Color.LimeGreen, true);
                    else
                        sprite.Draw(spriteBatch, true);
                }
            }
            else
            {
                sprite.currentFrame = 5;
                sprite.Draw(spriteBatch, !movingRight);
            }
        }

        public void RandomTaunt(GameTime time)
        {
            if (time.TotalGameTime.TotalMilliseconds - sTauntTimer > TAUNT_DELAY)
            {
                SoundManager.Instance.playSound(SoundManager.Sound.taunt, getPitch());
                sTauntTimer = time.TotalGameTime.TotalMilliseconds;
                TAUNT_DELAY = rand.Next(10000) + 10000;
            }
        }

        public float getPitch()
        {
            float pitch = 0;

            pitch = (-2 / (maxScale - minScale)) * sprite.Scale + 1;

            if (pitch >= 0.5f)
                pitch = 0.5f;
            else if (pitch <= 0.0f)
                pitch = 0.0f;

            return pitch;
        }

        public void UpdateSprite(GameTime time)
        {
            if (!starting && grounded && walking && (time.TotalGameTime.TotalMilliseconds - aWalkTimer >= WALK_DELAY))
            {
                if (sprite.currentFrame == JUMP1 || sprite.currentFrame == JUMP2)
                    sprite.currentFrame = WALK3;

                if (sprite.currentFrame == WALK3)
                    aWalkAniDir = -1;
                else if (sprite.currentFrame == WALK1)
                    aWalkAniDir = 1;

                sprite.currentFrame += aWalkAniDir;
                aWalkTimer = time.TotalGameTime.TotalMilliseconds;
            }
            else if ((vertSpeed < 0 && !grounded) || starting)
            {
                sprite.currentFrame = JUMP2;
            }
            else if (vertSpeed > 0)
            {
                sprite.currentFrame = JUMP1;
            }
            else if(grounded && !walking)
            {
                sprite.currentFrame = WALK3;
            }
        }

        public void AlterEnergy(float increment)
        {
            energy += increment;
        }
    }
}
